﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.XPath;
using System.Xml;
using FinanSoft.Entities;
using FinanSoft.Utilities;
using System.Collections.ObjectModel;
using FinanSoft.DataLayer;

namespace FinanSoft.BusinessLayer
{
    public class ConfigurationManager
    {
        #region Atributes
    
        private SpecialAccount[] _specialAccount;
        private List<Tax> _taxes;
        private bool _isError;
        private String _errorMessage;
        #endregion

        #region Properties
        public bool IsError
        {
            get
            {
                return _isError;
            }
        }

        public String ErrorMessage
        {
            get
            {
                return _errorMessage;
            }
        }
        #endregion

        #region Singleton


        private ConfigurationManager()
        {
            _isError = false;
            _errorMessage = "";
            _specialAccount = ConfigurationDataManager.GetInstance().GetSpecialAccountType();
            _taxes = ConfigurationDataManager.GetInstance().GetTaxes();
            if (_specialAccount == null)
            {
                _isError = true;
                _errorMessage = Constants.ERROR_SPECIAL_ACCOUNT_TYPE_READING;
            }
            if (_taxes == null)
            {
                _isError = true;
                _errorMessage = Constants.ERROR_IMPUESTOS_READING;
            }
            else
            {
                _isError = false;
            }
        }

        /// <summary>
        /// Única instancia de esta clase
        /// </summary>
        private static ConfigurationManager _instance;

        /// <summary>
        /// Método para implementar el patrón de Singleton
        /// </summary>
        /// <returns>Instancia única de la clase</returns>
        public static ConfigurationManager GetInstance()
        {
            if (_instance == null)
                _instance = new ConfigurationManager();
            return _instance;
        }
        #endregion

        #region Métodos

        public bool AddTax(string name, string code, float percentage)
        {
            Tax existingTax = GetTax(code);
            if (existingTax != null)
            {
                _isError = true;
                _errorMessage = Constants.ERROR_TAX_ALREADY_EXISTS;
                return false;
            }
            int newId = ConfigurationDataManager.GetInstance().AddTax(name, code, percentage);
            if (newId == Constants.INVALID_ID)
            {
                _isError = true;
                _errorMessage = Constants.ERROR_TAX_INSERTION_FAILED;
                return false;
            }
            else
            {
                _taxes.Add(new Tax(newId, name, code, percentage));
                return true;
            }
        }

        public bool DeleteTax(int id)
        {
            bool result = ConfigurationDataManager.GetInstance().DeleteTax(id);
            if (result)
            {
                _taxes.Remove(GetTax(id));
                return true;
            }
            else
            {
                _isError = true;
                _errorMessage = Constants.ERROR_TAX_DELETE_FAILED;
                return false;
            }
        }

        /// <summary>
        /// Metodo que retorna la lista de impuestos
        /// </summary>
        /// <returns></returns>
        public List<Tax> GetTaxes()
        {
            if (_taxes == null)
            {
                _isError = true;
                _errorMessage = Constants.ERROR_IMPUESTOS_READING;
            }
            return _taxes;
        }

        /// <summary>
        /// Obtiene el impuesto asociado a un acrónimo
        /// </summary>
        /// <param name="acronimo"></param>
        /// <returns></returns>
        public Tax GetTax(string acronimo)
        {
            foreach (Tax imp in _taxes)
                if (imp.Acronimo.Equals(acronimo))
                    return imp;
            return null;
        }

        /// <summary>
        /// Obtiene el impuesto con el Id dado
        /// </summary>
        /// <param name="taxId"></param>
        /// <returns></returns>
        public Tax GetTax(int taxId)
        {
            foreach (Tax tax in _taxes)
                if (tax.IdImpuesto == taxId)
                    return tax;
            return null;
        }

        /// <summary>
        /// Método que se encarga de retornar el impuesto por default
        /// para las compras de los clientes
        /// </summary>
        /// <returns>Retorna el impuesto del 13%</returns>
        public Tax GetDefaultTax()
        {
            return GetTax(Constants.DEFAULT_TAX13);
        }

        /// <summary>
        /// Método que se encarga de inicializar los Tipos de Cuentas Especiales
        /// </summary>
        /// <returns>Retorna el objeto cuenta especial con todos los Tipos de Cuentas Especiales</returns>
        public SpecialAccount[] GetSpecialAccountType()
        {

            if (_specialAccount == null)
            {
                _isError = true;
                Console.WriteLine("error y algo mas");
                _errorMessage = Constants.ERROR_SPECIAL_ACCOUNT_TYPE_READING;
                
            }
            _specialAccount = ConfigurationDataManager.GetInstance().GetSpecialAccountType();
            return _specialAccount;
        }

        /// <summary>
        /// Método que se encarga de inicializar las de Cuentas Especiales asignadas como de tipo
        /// de la cuenta especial seleccionada
        /// </summary>
        /// <returns>Retorna el objeto cuenta especial con todas cuentas de un tipo especial</returns>
        public SpecialAccount[] GetSpecialAccount(int idTipoCtaEsp)
        {

            if (_specialAccount == null)
            {
                _isError = true;
                Console.WriteLine("error y algo mas");
                _errorMessage = Constants.ERROR_SPECIAL_ACCOUNT_READING;

            }
            _specialAccount = ConfigurationDataManager.GetInstance().GetSpecialAccount(idTipoCtaEsp);
            return _specialAccount;
        }

        /// <summary>
        /// Método que se encarga de inicializar las de Cuentas Especiales no asignadas como de tipo
        /// de la cuenta especial seleccionada
        /// </summary>
        /// <returns>Retorna el objeto cuenta especial con todas cuentas que no son de un tipo especial</returns>
        public SpecialAccount[] GetNotSpecialAccount(int idTipoCtaEsp)
        {

            if (_specialAccount == null)
            {
                _isError = true;
                _errorMessage = Constants.ERROR_SPECIAL_ACCOUNT_TYPE_READING;

            }
            _specialAccount = ConfigurationDataManager.GetInstance().GetNotSpecialAccount(idTipoCtaEsp);
            List<SpecialAccount> finalList = new List<SpecialAccount>();
            foreach (SpecialAccount special in _specialAccount)
                if (CatalogManager.GetInstance().GetAccount(special.idCuenta).SpecialType == Constants.SpecialType.normal)
                    finalList.Add(special);
            return finalList.ToArray();
        }

        /// <summary>
        /// Método para agregar una nueva cuenta a un tipo de cuenta especial
        /// </summary>
        /// <returns>Retorna exito si se creo con exito</returns>
        public bool CreateNewSpecialAccount(int id, int idCta)
        {
            SpecialAccount newSpecialAccount = new SpecialAccount(id, idCta);

            bool noErrorDB = ConfigurationDataManager.GetInstance().CreateNewSpecialAccount(newSpecialAccount);
            if (!noErrorDB)
            {
                _isError = true;
                _errorMessage = Constants.ERROR_NEW_SPECIAL_ACCOUNT_FAILED;
                return false;
            }
            CatalogManager.GetInstance().Upload();
            return true;
        }

        /// <summary>
        /// Método para eliminar una nueva cuenta a un tipo de cuenta especial
        /// </summary>
        /// <returns>Retorna exito si se elimino con exito</returns>
        public bool DeleteSpecialAccount(int id, int idCta)
        {
            SpecialAccount newSpecialAccount = new SpecialAccount(id, idCta);

            bool noErrorDB = ConfigurationDataManager.GetInstance().DeleteNewSpecialAccount(newSpecialAccount);
            if (!noErrorDB)
            {
                _isError = true;
                _errorMessage = Constants.ERROR_DELETE_SPECIAL_ACCOUNT_FAILED;


                return false;
            }
            CatalogManager.GetInstance().Upload();
            return true;
        }        

        #endregion
    }
}
